package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.sc.nft.config.fulu.model.dto.ElementInfoDTO;
import com.sc.nft.dao.DigitalCollectionDao;
import com.sc.nft.dao.EquityPropsDao;
import com.sc.nft.dao.MallActivityDao;
import com.sc.nft.dao.MallActivityExchangeDao;
import com.sc.nft.dao.MallActivitySpecsDao;
import com.sc.nft.dao.MallGoodsLabelDao;
import com.sc.nft.dao.MallHotSaleActivityDao;
import com.sc.nft.dao.MallMemberDao;
import com.sc.nft.dao.MallMemberEquityDao;
import com.sc.nft.dao.MallMemberEquityTargetDao;
import com.sc.nft.dao.MallMemberEquityTemplateDao;
import com.sc.nft.dao.MallProductAttributeDao;
import com.sc.nft.dao.MallProductSpecsDao;
import com.sc.nft.dao.StaticDataDao;
import com.sc.nft.dao.UserAssetsDao;
import com.sc.nft.dao.UserCollectionDao;
import com.sc.nft.dao.UserCreatorInfoDao;
import com.sc.nft.dao.UserEquityPropsDao;
import com.sc.nft.dao.WxMiniUserInfoDao;
import com.sc.nft.dto.*;
import com.sc.nft.entity.DigitalCollection;
import com.sc.nft.entity.EquityProps;
import com.sc.nft.entity.MallActivity;
import com.sc.nft.entity.MallActivityExchange;
import com.sc.nft.entity.MallActivityShare;
import com.sc.nft.entity.MallActivityShareSpecs;
import com.sc.nft.entity.MallActivitySpecs;
import com.sc.nft.entity.MallGoodsLabel;
import com.sc.nft.entity.MallMember;
import com.sc.nft.entity.MallProduct;
import com.sc.nft.entity.MallProductAttribute;
import com.sc.nft.entity.MallProductSpecs;
import com.sc.nft.entity.MallProfitTemplate;
import com.sc.nft.entity.MallUserActivitySummary;
import com.sc.nft.entity.UserAssets;
import com.sc.nft.entity.UserCreatorInfo;
import com.sc.nft.entity.UserInfo;
import com.sc.nft.entity.WxMiniUserInfo;
import com.sc.nft.entity.dto.ActivityCouponsProductDTO;
import com.sc.nft.entity.dto.ActivityShareProductDTO;
import com.sc.nft.entity.dto.AttributeDetailDTO;
import com.sc.nft.entity.dto.BuyLimitDTO;
import com.sc.nft.entity.dto.MallMemberCheckHasPreemptionDTO;
import com.sc.nft.entity.dto.PreferenceActivityDTO;
import com.sc.nft.entity.vo.MallActivityUpdateShowChannelVO;
import com.sc.nft.entity.vo.mall.ActivityDetailV2VO;
import com.sc.nft.entity.vo.mall.ActivityDetailVO;
import com.sc.nft.entity.vo.mall.ActivityExchangeV2VO;
import com.sc.nft.entity.vo.mall.ActivityExchangeVO;
import com.sc.nft.entity.vo.mall.ActivityMiniMallDetailVO;
import com.sc.nft.entity.vo.mall.ActivityPageVO;
import com.sc.nft.entity.vo.mall.ActivitySpecsVO;
import com.sc.nft.entity.vo.mall.AdminSalesPageVO;
import com.sc.nft.entity.vo.mall.BargainPriceProductPageVO;
import com.sc.nft.entity.vo.mall.CategoryProductPageVO;
import com.sc.nft.entity.vo.mall.HotSaleActivityPageVO;
import com.sc.nft.entity.vo.mall.MallActivitySalesPriceUpdateVO;
import com.sc.nft.entity.vo.mall.MallActivityStockUpdateVO;
import com.sc.nft.entity.vo.mall.MallProductLabelVO;
import com.sc.nft.enums.ApprovalStatusEnum;
import com.sc.nft.enums.CoinCategoryEnum;
import com.sc.nft.enums.MallActivityShowChannelEnum;
import com.sc.nft.enums.MallBuyLimitTypeEnum;
import com.sc.nft.enums.MallExchangeEnum;
import com.sc.nft.enums.MallGoodsLabelEnums;
import com.sc.nft.enums.MiniMallMemberEquityEnums;
import com.sc.nft.enums.ProductTypeEnum;
import com.sc.nft.enums.mallcart.CartExpiredEnum;
import com.sc.nft.enums.task.ActivityTypeEnum;
import com.sc.nft.enums.task.ParticipantsEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.feign.WxMiniPointsRuleClient;
import com.sc.nft.feign.WxMiniProfitTemplateClient;
import com.sc.nft.service.MallActivityExchangeService;
import com.sc.nft.service.MallActivityService;
import com.sc.nft.service.MallActivityShareService;
import com.sc.nft.service.MallActivityShareSpecsService;
import com.sc.nft.service.MallActivitySpecsService;
import com.sc.nft.service.MallMemberEquityService;
import com.sc.nft.service.MallOrderProductService;
import com.sc.nft.service.MallProductService;
import com.sc.nft.service.MallProfitTemplateService;
import com.sc.nft.service.MallUserActivitySummaryService;
import com.sc.nft.service.UserCollectionService;
import com.sc.nft.service.UserEquityPropsService;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.util.BigDecimalUtils;
import com.sc.nft.vo.pointsrule.PointsRuleDetailsVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * IP商城营销活动表服务接口实现
 *
 * @author zxy
 * @description IP商城
 * @since 2023-05-10 16:59:01
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class MallActivityServiceImpl implements MallActivityService {
    private final MallActivityDao mallActivityDao;
    private final MallActivitySpecsDao mallActivitySpecsDao;
    private final MallProductSpecsDao mallProductSpecsDao;
    private final MallProductService mallProductService;
    private final MallActivityExchangeDao mallActivityExchangeDao;
    private final EquityPropsDao equityPropsDao;
    private final DigitalCollectionDao digitalCollectionDao;
    private final UserAssetsDao userAssetsDao;
    private final UserEquityPropsDao userEquityPropsDao;
    private final UserCollectionDao userCollectionDao;
    private final UserCreatorInfoDao userCreatorInfoDao;
    private final MallHotSaleActivityDao mallHotSaleActivityDao;
    private final MallActivitySpecsService mallActivitySpecsService;
    private final MallProductAttributeDao mallProductAttributeDao;
    private final UserEquityPropsService userEquityPropsService;
    private final UserCollectionService userCollectionService;
    private final MallOrderProductService mallOrderProductService;
    private final MallActivityExchangeService mallActivityExchangeService;
    @Autowired
    MallActivityShareService mallActivityShareService;
    private final MallActivityShareSpecsService mallActivityShareSpecsService;
    private final StaticDataDao staticDataDao;
    private final MallProfitTemplateService mallProfitTemplateService;
    private final MallMemberEquityDao mallMemberEquityDao;
    private final MallMemberEquityTargetDao mallMemberEquityTargetDao;
    private final MallMemberEquityTemplateDao mallMemberEquityTemplateDao;
    private final MallMemberEquityService mallMemberEquityService;
    private final WxMiniPointsRuleClient wxMiniPointsRuleClient;
    private final MallMemberDao mallMemberDao;
    private final WxMiniUserInfoDao wxMiniUserInfoDao;
    private final WxMiniProfitTemplateClient wxMiniProfitTemplateClient;
    private final MallGoodsLabelDao mallGoodsLabelDao;
    private final MallUserActivitySummaryService mallUserActivitySummaryService;

    @Override
    public List<MallActivity> queryFinishedActivities() {
        return mallActivityDao.queryFinishedActivities();
    }

    @Override
    public MallActivity getByIdAndApprovalStatus(Long activityId, ApprovalStatusEnum approvalStatus) {
        return mallActivityDao.getByIdAndApprovalStatus(activityId, approvalStatus);
    }

    @Override
    public MallActivity getCanBuy(Long activityId) {
        return mallActivityDao.getCanBuy(activityId);
    }

    @Override
    public IPage<ActivityPageDTO> queryActivity(Long daoId, Boolean status, Boolean recommend, ApprovalStatusEnum approvalStatus, ProductTypeEnum productType, ActivityTypeEnum activityType, String productName, Boolean isMiniMall, Page toMp) {
        IPage<ActivityPageDTO> activityPageDTOIPage = mallActivityDao.queryActivity(daoId, status, recommend, approvalStatus, productType, activityType, productName, isMiniMall, toMp);
        for (ActivityPageDTO record : activityPageDTOIPage.getRecords()) {
            record.setCoverImages(StrUtil.split(record.getCoverImage(), ","));
            record.setMainImages(record.getCoverImages().get(0));
            if (StringUtils.isNotBlank(record.getShowChannel())) {
                record.setShowChannelList(JSONArray.parseArray(record.getShowChannel(), Long.class));
            }
        }
        return activityPageDTOIPage;
    }

    @Override
    public IPage<ActivityPageVO> activityPage(Long daoId, Long categoryId, ActivityTypeEnum activityType, ProductTypeEnum type, String productName, Page page, Boolean isSaas, Boolean isMiniMall) {
        String restrictDaoIdStr = staticDataDao.getByType("restrict_dao_id").getValue();
        Long restrictDaoId = Long.valueOf(restrictDaoIdStr);
        Integer isShow = MallActivityShowChannelEnum.SHOW_DAO.getCode();
        if (isSaas) {
            isShow = MallActivityShowChannelEnum.SHOW_SAAS_DAO.getCode();
        }
        IPage<ActivityPageVO> activityPage = mallActivityDao.activityPage(daoId, categoryId, activityType, type, productName, page, isShow, isMiniMall);
        for (ActivityPageVO record : activityPage.getRecords()) {
            if (record.getSpecsCount() > 1) {
                record.setSalesPrice(record.getSalesPrice() + "起");
            }
            if (StrUtil.isNotBlank(record.getCoverImage())) {
                record.setCoverImage(StrUtil.split(record.getCoverImage(), ",").get(0));
            }
            if (record.getActivityType() == ActivityTypeEnum.EXCHANGE) {
                List<ActivityExchangeVO> exchangeDTOS = Lists.newArrayList();
                List<MallActivityExchange> exchanges = mallActivityExchangeDao.getByActivityId(record.getActivityId());
                for (MallActivityExchange exchange : exchanges) {
                    ActivityExchangeVO activitySpecsExchangeDTO = new ActivityExchangeVO();
                    activitySpecsExchangeDTO.setType(1);
                    activitySpecsExchangeDTO.setName(exchange.getLinkName());
                    activitySpecsExchangeDTO.setCount(exchange.getCostNum());
                    activitySpecsExchangeDTO.setLinkImage(exchange.getLinkImage());
                    exchangeDTOS.add(activitySpecsExchangeDTO);
                }
                record.setActivityExchanges(exchangeDTOS);
            }
            //判断标签
            if (record.getLabelType() != null) {
                if (record.getLabelType() == MallGoodsLabelEnums.NEW_LABEL) {
                    //新品，判断商品的创建时间是否大于标签的创建时间
                    if (record.getLabelStartTime().after(record.getCreateTime()) || !DateUtil.isIn(new Date(), record.getLabelStartTime(), record.getLabelEndTime())) {
                        record.setLabelImage(null);
                    }
                } else if (record.getLabelType() == MallGoodsLabelEnums.ACTIVITY_LABEL) {
                    //活动
                    if (!DateUtil.isIn(new Date(), record.getLabelStartTime(), record.getLabelEndTime())) {
                        record.setLabelImage(null);
                    }
                }
            }
        }
        return activityPage;
    }


    @Override
    public List<String> getThreeImage() {
        List<String> result = Lists.newArrayList();
        List<Long> threeProductId = mallActivityDao.getThreeProductId();
        for (Long aLong : threeProductId) {
            MallProduct product = mallProductService.getById(aLong);
            if (ObjectUtil.isNotNull(product)) {
                result.add(product.getCoverImage().split(",")[0]);
            }
        }
        return result;
    }

    @Override
    public ActivityDTO detail(Long id) {
        MallActivity activity = mallActivityDao.getById(id);
        Assert.notNull(activity, () -> new GlobalRunTimeException("活动不存在"));
        MallProduct product = mallProductService.getById(activity.getProductId());
        Assert.notNull(product, () -> new GlobalRunTimeException("商品不存在"));
        ActivityDTO activityDTO = new ActivityDTO();
        activityDTO.setDaoid(activity.getDaoId());
        activityDTO.setId(activity.getId());
        activityDTO.setProductId(activity.getProductId());
        activityDTO.setProductName(product.getProductName());
        activityDTO.setApprovalStatus(activity.getApprovalStatus());
        activityDTO.setRemark(activity.getRemark());
        activityDTO.setSort(activity.getSort());
        activityDTO.setActivityType(activity.getActivityType());
        activityDTO.setMallSort(activity.getMallSort());
        activityDTO.setBuyLimit(activity.getBuyLimit());
        activityDTO.setBuyLimitType(activity.getBuyLimitType());
        activityDTO.setExchangeAmount(activity.getExchangeAmount());
        activityDTO.setStartTime(activity.getStartTime());
        activityDTO.setEndTime(activity.getEndTime());
        activityDTO.setParticipants(activity.getParticipants());
        if (activityDTO.getParticipants() == ParticipantsEnum.APPOINT) {
            activityDTO.setCollectionId(activity.getCollectionId());
            DigitalCollection collection = digitalCollectionDao.getById(activity.getCollectionId());
            activityDTO.setFirstTitle(collection.getFirstTitle());
        }
        List<MallActivitySpecs> mallActivitySpecs = mallActivitySpecsDao.getByActivityId(activity.getId());
        List<ActivitySpecsDTO> specsDTOS = Lists.newArrayList();
        for (MallActivitySpecs mallActivitySpec : mallActivitySpecs) {
            ActivitySpecsDTO activitySpecsDTO = new ActivitySpecsDTO();
            activitySpecsDTO.setId(mallActivitySpec.getId());
            activitySpecsDTO.setSpecsId(mallActivitySpec.getSpecsId());
            MallProductSpecs specs = mallProductSpecsDao.getById(mallActivitySpec.getSpecsId());

            activitySpecsDTO.setThumbnail(specs.getThumbnail());
            activitySpecsDTO.setSpecsName(specs.getSpecsName());
            activitySpecsDTO.setSpecsCode(specs.getSpecsCode());
            activitySpecsDTO.setCostPrice(mallActivitySpec.getCostPrice());
            activitySpecsDTO.setActivityCostPrice(mallActivitySpec.getActivityCostPrice());
            activitySpecsDTO.setReservePrice(mallActivitySpec.getReservePrice());
            activitySpecsDTO.setStockCount(mallActivitySpec.getUsableStockCount());
            activitySpecsDTO.setSumStockCount(mallActivitySpec.getSumStockCount());
            activitySpecsDTO.setSalesPrice(mallActivitySpec.getSalesPrice());
            activitySpecsDTO.setProfit(mallActivitySpec.getProfit());
            activitySpecsDTO.setSendCode(specs.getSendCode());
            activitySpecsDTO.setProfitTemplateId(mallActivitySpec.getProfitTemplateId());
            activitySpecsDTO.setPropsId(mallActivitySpec.getPropsId());
            activitySpecsDTO.setPropsRewardNum(mallActivitySpec.getPropsRewardNum());
            if (mallActivitySpec.getPropsId() != null) {
                EquityProps equityProps = equityPropsDao.getById(mallActivitySpec.getPropsId());
                if (equityProps != null) {
                    activitySpecsDTO.setFirstTitle(equityProps.getFirstTitle());
                }
            }

            if (Objects.nonNull(mallActivitySpec.getProfitTemplateId())) {
                MallProfitTemplate mallProfitTemplate = mallProfitTemplateService.getById(mallActivitySpec.getProfitTemplateId());
                if (Objects.nonNull(mallProfitTemplate)) {
                    activitySpecsDTO.setProfitTemplateName(mallProfitTemplate.getTemplateName());
                }
            }
            specsDTOS.add(activitySpecsDTO);
        }
        activityDTO.setSpecsDTOS(specsDTOS);
        List<MallActivityExchange> exchanges = mallActivityExchangeDao.getByActivityId(activity.getId());
        List<ActivitySpecsExchangeDTO> exchangeDTOS = Lists.newArrayList();
        for (MallActivityExchange exchange : exchanges) {
            ActivitySpecsExchangeDTO activitySpecsExchangeDTO = new ActivitySpecsExchangeDTO();
            activitySpecsExchangeDTO.setExchangeType(exchange.getType());
            activitySpecsExchangeDTO.setCostNum(exchange.getCostNum());
            activitySpecsExchangeDTO.setCollectionId(exchange.getActivityId());
            activitySpecsExchangeDTO.setEquityId(exchange.getActivitySpecsId());
            activitySpecsExchangeDTO.setLinkName(exchange.getLinkName());
            activitySpecsExchangeDTO.setGroupId(exchange.getGroupId());
            exchangeDTOS.add(activitySpecsExchangeDTO);
        }

        Map<Long, List<ActivitySpecsExchangeDTO>> collect = exchangeDTOS.stream().collect(Collectors.groupingBy(ActivitySpecsExchangeDTO::getGroupId,TreeMap::new, Collectors.toList()));

        List<ListActivitySpecsExchangeDTO> listActivitySpecsExchangeDTO = new ArrayList<>();

        for (List<ActivitySpecsExchangeDTO> value : collect.values()) {
            ListActivitySpecsExchangeDTO activitySpecsExchangeDTO = new ListActivitySpecsExchangeDTO();
            if(CollUtil.isNotEmpty(value)){
                List<ActivitySpecsExchangeDTO> needToDistinct = value;
                needToDistinct.stream().forEach(e->e.setEquityId(1L));
                List<ActivitySpecsExchangeDTO> collect1 = needToDistinct.stream().distinct().collect(Collectors.toList());
                activitySpecsExchangeDTO.setExchangeDTOS(collect1);
                Optional.ofNullable(collect1)
                        .filter(v -> !v.isEmpty())
                        .map(v -> v.get(0).getGroupId())
                        .map(Object::toString)
                        .ifPresent(activitySpecsExchangeDTO::setGroupId);
                listActivitySpecsExchangeDTO.add(activitySpecsExchangeDTO);
            }
        }

        activityDTO.setExchangeDTOSList(listActivitySpecsExchangeDTO);
        return activityDTO;
    }

    @Override
    public BuyLimitDTO convertBuyLimit(MallActivity activity, MallUserActivitySummary mallUserActivitySummary) {
        if (activity.getBuyLimitType() == MallBuyLimitTypeEnum.FIXED) {
            BuyLimitDTO buyLimitDTO = new BuyLimitDTO();
            buyLimitDTO.setBuyLimit(activity.getBuyLimit());
            return buyLimitDTO;
        }
        //通过累计金额算出需要多少个藏品
        //兑换1件商品的金额
        BigDecimal exchangeAmount = activity.getExchangeAmount() == null ? BigDecimal.ZERO : activity.getExchangeAmount();
        BigDecimal totalConsumptionAmount = BigDecimal.ZERO;
        BigDecimal totalExchangeAmount = BigDecimal.ZERO;
        if (mallUserActivitySummary != null) {
            totalConsumptionAmount = mallUserActivitySummary.getTotalConsumptionAmount() == null ? BigDecimal.ZERO : mallUserActivitySummary.getTotalConsumptionAmount();
            totalExchangeAmount = mallUserActivitySummary.getTotalExchangeAmount() == null ? BigDecimal.ZERO : mallUserActivitySummary.getTotalExchangeAmount();
        }
        BigDecimal remainingRedemptionAmount = totalConsumptionAmount.subtract(totalExchangeAmount);
        Integer buyLimit = 0;
        if (remainingRedemptionAmount.compareTo(BigDecimal.ZERO) > 0) {
            buyLimit = remainingRedemptionAmount.divide(exchangeAmount, 0, RoundingMode.DOWN).intValue();
        }
        BuyLimitDTO buyLimitDTO = new BuyLimitDTO();
        buyLimitDTO.setBuyLimit(buyLimit);
        buyLimitDTO.setBuyLimitStr("每消费" + exchangeAmount + "元可兑换1件，当前消费" + remainingRedemptionAmount + "元，可兑换" + buyLimit + "件");
        return buyLimitDTO;
    }

    @Override
    public ActivityDetailVO activityDetail(UserInfo userInfo, Long id, Long shareTeamId, ActivityTypeEnum exchangeForActivity) {
        MallActivity activity = mallActivityDao.getById(id);
        // 分享购拼团
        MallActivityShare mallActivityShare = null;
        if (Objects.nonNull(shareTeamId)) {
            mallActivityShare = mallActivityShareService.getByTeamId(shareTeamId);
            if (!mallActivityShare.getStatus()) {
                throw new GlobalRunTimeException("活动已结束");
            }
        }
        Assert.notNull(activity, () -> new GlobalRunTimeException("活动已结束"));
        Assert.isTrue(activity.getStatus(), () -> new GlobalRunTimeException("活动已结束"));

        MallProduct product = mallProductService.getById(activity.getProductId());
        ActivityDetailVO activityDTO = new ActivityDetailVO();
        activityDTO.setActivityId(activity.getId());
        activityDTO.setActivityType(activity.getActivityType());
        activityDTO.setType(product.getType());
        activityDTO.setCategoryId(product.getCategoryId());
        activityDTO.setCoverImages(StrUtil.split(product.getCoverImage(), ","));
        activityDTO.setThumbnail(product.getThumbnail());
        activityDTO.setStatus(activity.getStatus());
        activityDTO.setBuyLimitType(activity.getBuyLimitType());
        MallUserActivitySummary mallUserActivitySummary = mallUserActivitySummaryService.get(userInfo.getId());
        BuyLimitDTO buyLimitDTO = this.convertBuyLimit(activity, mallUserActivitySummary);
        activityDTO.setBuyLimit(buyLimitDTO.getBuyLimit());
        activityDTO.setBuyLimitStr(buyLimitDTO.getBuyLimitStr());
        activityDTO.setBuyLimitType(activity.getBuyLimitType());
        activityDTO.setStartTime(activity.getStartTime());
        activityDTO.setProductCode(product.getProductCode());
        activityDTO.setProductName(product.getProductName());
        activityDTO.setProductDetail(StrUtil.split(product.getProductDetail(), ","));
        activityDTO.setAllReadyStart(DateTime.now().after(activity.getStartTime()));
        activityDTO.setAllowedShoppingCoupons(product.isAllowedShoppingCoupons());
        if (Objects.nonNull(product.getAttributeId())) {
            // 属性
            MallProductAttribute productAttribute = mallProductAttributeDao.getById(product.getAttributeId());
            if (StringUtils.isNotBlank(productAttribute.getAttributeDetail())) {
                List<AttributeDetailDTO> attributeDetailDTOS = JSONArray.parseArray(productAttribute.getAttributeDetail(), AttributeDetailDTO.class);
                activityDTO.setAttributeDetailDTOList(attributeDetailDTOS);
                activityDTO.setAttributeName(productAttribute.getAttributeName());
            }
        }
        UserCreatorInfo dao = userCreatorInfoDao.getById(activity.getDaoId());
        activityDTO.setDaoName(dao.getDaoName());
        activityDTO.setDaoId(dao.getId());
        activityDTO.setIsDao(dao.getStatus());
        activityDTO.setDaoImg(dao.getCreatorAvatarImg());

        List<MallActivitySpecs> mallActivitySpecs = mallActivitySpecsDao.getByActivityId(activity.getId());
        if (Objects.nonNull(mallActivityShare)) {
            // 存在拼团价
            List<MallActivityShareSpecs> mallActivityShareSpecs = mallActivityShareSpecsService.getMallActivityShareSpecs(mallActivityShare.getId());
            Map<Long, BigDecimal> mallActivityShareSpecsMap = mallActivityShareSpecs.stream().collect(Collectors.toMap(MallActivityShareSpecs::getActivitySpecsId, MallActivityShareSpecs::getSalesPrice, (value1, value2) -> value1));
            for (MallActivitySpecs mallActivitySpec : mallActivitySpecs) {
                BigDecimal shareSalesPrice = mallActivityShareSpecsMap.get(mallActivitySpec.getId());
                if (Objects.nonNull(shareSalesPrice) && BigDecimalUtils.greaterZero(shareSalesPrice)) {
                    mallActivitySpec.setSalesPrice(shareSalesPrice);
                }
            }

        }
        if (activityDTO.getActivityType() == ActivityTypeEnum.SALES) {
            String salesPrice = mallActivitySpecs.stream().map(MallActivitySpecs::getSalesPrice).min(BigDecimal::compareTo).get().toPlainString();
            activityDTO.setMinPrice(salesPrice);
            activityDTO.setMaxPrice(mallActivitySpecs.stream().map(MallActivitySpecs::getSalesPrice).max(BigDecimal::compareTo).get().toPlainString());
            if (mallActivitySpecs.size() > 1) {
                salesPrice += "起";
            }
            activityDTO.setSalesPrice(salesPrice);
        }
        List<ActivitySpecsVO> specsDTOS = Lists.newArrayList();
        int sumUsableCount = 0;
        int sumCount = 0;
        for (MallActivitySpecs mallActivitySpec : mallActivitySpecs) {
            ActivitySpecsVO activitySpecsDTO = new ActivitySpecsVO();
            activitySpecsDTO.setActivitySpecsId(mallActivitySpec.getId());
            MallProductSpecs specs = mallProductSpecsDao.getById(mallActivitySpec.getSpecsId());
            if (StringUtils.isNotBlank(specs.getApiProductElementInfo())) {
                ElementInfoDTO elementInfoDTO = JSON.parseObject(specs.getApiProductElementInfo(), ElementInfoDTO.class);
                activitySpecsDTO.setElementInfoDTO(elementInfoDTO);
            }
            activitySpecsDTO.setThumbnail(specs.getThumbnail());
            activitySpecsDTO.setSpecsName(specs.getSpecsName());
            activitySpecsDTO.setSpecsCode(specs.getSpecsCode());
            activitySpecsDTO.setSalesPrice(mallActivitySpec.getSalesPrice().toPlainString());
            activitySpecsDTO.setUsableCount(mallActivitySpec.getUsableStockCount());
            sumUsableCount += mallActivitySpec.getUsableStockCount();
            sumCount += mallActivitySpec.getSumStockCount();
            specsDTOS.add(activitySpecsDTO);
        }
        activityDTO.setSumCount(sumCount);
        activityDTO.setStockEnough(sumUsableCount > 0);
        activityDTO.setActivitySpecs(specsDTOS);
        List<MallActivityExchange> exchangesList = mallActivityExchangeDao.getByActivityId(activity.getId());
        List<MallActivityExchange> exchanges = exchangeDistinctOld(exchangesList);
        List<ActivityExchangeVO> exchangeDTOS = Lists.newArrayList();

        int totalCostNum = 0;
        int equityCostNum = 0;
        int nftCostNum = 0;
        Integer userBuyCount = mallOrderProductService.getUserBuyCountByUserIdAndActivityId(userInfo.getId(), activity.getId());
        if (BeanUtil.isNotEmpty(activity) && activity.getActivityType().equals(ActivityTypeEnum.EXCHANGE)) {
            //exchanges 单位积分、权益道具、nft
            if (userBuyCount.equals(activityDTO.getBuyLimit())) {
                activityDTO.setExchangePropEnough(Boolean.FALSE);
            }
            totalCostNum = exchanges.stream().filter(exchange -> exchange.getType() == MallExchangeEnum.INTEGRAL).mapToInt(MallActivityExchange::getCostNum).sum();
            equityCostNum = exchanges.stream().filter(exchange -> exchange.getType() == MallExchangeEnum.EQUITY).mapToInt(MallActivityExchange::getCostNum).sum();
            nftCostNum = exchanges.stream().filter(exchange -> exchange.getType() == MallExchangeEnum.NFT).mapToInt(MallActivityExchange::getCostNum).sum();
        }
        UserAssets userAssets = userAssetsDao.getByUserIdAndCoinId(userInfo.getId(), CoinCategoryEnum.INTEGRAL.getCode());
        BigDecimal maxTotalNumIn = BigDecimal.valueOf(activityDTO.getBuyLimit());
        BigDecimal maxTotalNumEq = BigDecimal.valueOf(activityDTO.getBuyLimit());
        BigDecimal maxTotalNumNft = BigDecimal.valueOf(activityDTO.getBuyLimit());
        for (MallActivityExchange exchange : exchanges) {
            ActivityExchangeVO activitySpecsExchangeDTO = new ActivityExchangeVO();
            activitySpecsExchangeDTO.setType(1);
            activitySpecsExchangeDTO.setExchangeType(exchange.getType());
            activitySpecsExchangeDTO.setName(exchange.getLinkName());
            activitySpecsExchangeDTO.setLinkImage(exchange.getLinkImage());
            BigDecimal buyLimit = BigDecimal.valueOf(activityDTO.getBuyLimit());
            switch (exchange.getType()) {
                case INTEGRAL:
                    if (ObjectUtil.isNotNull(userInfo)) {
                        activitySpecsExchangeDTO.setHoldCount(userAssets.getTokenNum().toPlainString());
                    } else {
                        activitySpecsExchangeDTO.setHoldCount("0");
                    }
                    Integer usableStockCount = mallActivitySpecs.get(0).getUsableStockCount();
                    if (mallActivitySpecs.get(0).getUsableStockCount() < 0) {
                        activityDTO.setExchangePropEnough(Boolean.FALSE);
                    }
                    //如果库存不足
                    activityDTO.setMaxTotalNum(BigDecimal.valueOf(usableStockCount).min(BigDecimal.valueOf(activityDTO.getBuyLimit()).subtract(BigDecimal.valueOf(userBuyCount))));
                    //用户上限还可以买多少个 还需要判断消耗道具是否充足
                    if (ObjectUtil.isNotNull(exchangeForActivity) && exchangeForActivity.equals(ActivityTypeEnum.EXCHANGE)) {
                        BigDecimal tokenNum = new BigDecimal(activitySpecsExchangeDTO.getHoldCount());
                        if (totalCostNum != 0 && tokenNum.compareTo(BigDecimal.ZERO) != 0) {
                            maxTotalNumIn = userAssets.getTokenNum().divide(BigDecimal.valueOf(totalCostNum), 0, BigDecimal.ROUND_DOWN);
                            activityDTO.setMaxTotalNum(buyLimit.subtract(BigDecimal.valueOf(userBuyCount)).min(maxTotalNumIn));
                            activityDTO.setExchangePropEnough(Boolean.TRUE);
                            if (activityDTO.getMaxTotalNum().compareTo(BigDecimal.ZERO) <= 0) {
                                activityDTO.setExchangePropEnough(Boolean.FALSE);
                            }
                        }
                    }
                    break;
                case EQUITY:
                    if (ObjectUtil.isNotNull(userInfo)) {
                        //这里没拿到权益道具数量
                        Integer count = userEquityPropsDao.getHavingCountByUserId(exchange.getLinkId(), userInfo.getId());
                        activitySpecsExchangeDTO.setHoldCount(count.toString());
                    } else {
                        activitySpecsExchangeDTO.setHoldCount("0");
                    }
                    if (ObjectUtil.isNotNull(exchangeForActivity) && exchangeForActivity.equals(ActivityTypeEnum.EXCHANGE)) {
                        //单位商品的道具消耗数量 equityCostNum
                        BigDecimal tokenNum = new BigDecimal(activitySpecsExchangeDTO.getHoldCount());
                        maxTotalNumEq = tokenNum.divide(BigDecimal.valueOf(equityCostNum), 0, BigDecimal.ROUND_DOWN);
                        //用户持有的权益道具数量
                        activityDTO.setMaxTotalNum(buyLimit.subtract(BigDecimal.valueOf(userBuyCount)).min(maxTotalNumEq));
                        activityDTO.setExchangePropEnough(Boolean.TRUE);
                        if (activityDTO.getMaxTotalNum().compareTo(BigDecimal.ZERO) <= 0) {
                            activityDTO.setExchangePropEnough(Boolean.FALSE);
                        }
                    }
                    break;
                case NFT:
                    if (ObjectUtil.isNotNull(userInfo)) {
                        //nft数量
                        Integer count = userCollectionDao.getCountByCollectionNotConsignId(exchange.getLinkId(), userInfo.getId());
                        activitySpecsExchangeDTO.setHoldCount(count.toString());
                    } else {
                        activitySpecsExchangeDTO.setHoldCount("0");
                    }
                    if (ObjectUtil.isNotNull(exchangeForActivity) && exchangeForActivity.equals(ActivityTypeEnum.EXCHANGE)) {
                        BigDecimal tokenNum = new BigDecimal(activitySpecsExchangeDTO.getHoldCount());
                        maxTotalNumNft = tokenNum.divide(BigDecimal.valueOf(nftCostNum), 0, BigDecimal.ROUND_DOWN);
                        //用户持有的权益道具数量
                        activityDTO.setMaxTotalNum(buyLimit.subtract(BigDecimal.valueOf(userBuyCount)).min(maxTotalNumNft));
                        activityDTO.setExchangePropEnough(Boolean.TRUE);
                        if (activityDTO.getMaxTotalNum().compareTo(BigDecimal.ZERO) <= 0) {
                            activityDTO.setExchangePropEnough(Boolean.FALSE);
                        }
                    }
                    break;
            }
            activitySpecsExchangeDTO.setCount(exchange.getCostNum());
            //用户上限还可以兑换几个 添加默认值
            log.debug("最大可兑换数量为：", activityDTO.getMaxTotalNum());
            if (Objects.isNull(activityDTO.getMaxTotalNum()) || activityDTO.getMaxTotalNum().compareTo(BigDecimal.ZERO) <= 0) {
                log.debug("覆盖了最大可兑换数量：", activityDTO.getMaxTotalNum());
                activityDTO.setMaxTotalNum(BigDecimal.ZERO);
                activityDTO.setExchangePropEnough(Boolean.FALSE);
            }
            exchangeDTOS.add(activitySpecsExchangeDTO);
        }
        //积分 权益道具 nft 三者取最小
        activityDTO.setMaxTotalNum(maxTotalNumIn.min(maxTotalNumEq).min(maxTotalNumNft));
        if (ObjectUtil.isNotNull(userInfo)) {
            if (activity.getParticipants() == ParticipantsEnum.APPOINT) {
                ActivityExchangeVO activitySpecsExchangeDTO = new ActivityExchangeVO();
                activitySpecsExchangeDTO.setType(2);
                DigitalCollection collection = digitalCollectionDao.getById(activity.getCollectionId());
                activitySpecsExchangeDTO.setName(collection.getFirstTitle());
                activitySpecsExchangeDTO.setCount(1);
                activitySpecsExchangeDTO.setHoldCount(String.valueOf(userCollectionDao.getByUserIdAndCollectionIdCount(userInfo.getId(), activity.getCollectionId())));
                activitySpecsExchangeDTO.setLinkImage(collection.getCreationContent());
                exchangeDTOS.add(activitySpecsExchangeDTO);
            }
        }
        boolean checkExchange = true;
        for (ActivityExchangeVO exchangeDTO : exchangeDTOS) {
            if (NumberUtil.isGreater(BigDecimal.valueOf(exchangeDTO.getCount()), new BigDecimal(exchangeDTO.getHoldCount()))) {
                checkExchange = false;
                break;
            }
        }
        if (activity.getBuyLimitType() == MallBuyLimitTypeEnum.DYNAMIC) {
            if (checkExchange && buyLimitDTO.getBuyLimit() <= 0) {
                checkExchange = false;
            }
        }
        activityDTO.setCheckExchange(checkExchange);
        activityDTO.setActivityExchanges(exchangeDTOS);
        // 判断是否有拼团活动
        Boolean hasShare = mallActivityShareService.hasShareByActivityId(id);
        activityDTO.setIsHasActivityShare(hasShare);
        //判断是否有会员优先抢的权益
        MallMemberCheckHasPreemptionDTO checkHasPreemptionDTO = mallMemberEquityService.checkHasPreemption(userInfo, mallActivitySpecs.get(0).getId());
        //优先购泡判断条件 1.有优先购的权限，并且是活动时间之前（正常活动时间倒推至权益设置提前时间的中间）
        if (Objects.nonNull(checkHasPreemptionDTO)) {
            //判断时间现在是否能为优先购时间
            DateTime checkTime = DateUtil.offsetMinute(activity.getStartTime(), -checkHasPreemptionDTO.getPrioritizeTheLeadTime());
            if (DateUtil.isIn(DateTime.now(), checkTime, activity.getStartTime())) {
                activityDTO.setIsHasPreemption(Boolean.TRUE);
                activityDTO.setAllReadyStart(DateTime.now().after(checkTime));
            }
            activityDTO.setStartTime(checkTime);
        }
        //查询商品绑定的标签
        List<MallGoodsLabel> mallGoodsLabelList = mallGoodsLabelDao.productDetailsGetLabel(activity.getId());
        if (!CollectionUtils.isEmpty(mallGoodsLabelList)) {
            List<MallProductLabelVO> labelList = new ArrayList<>();
            for (MallGoodsLabel mallGoodsLabel : mallGoodsLabelList) {
                if (mallGoodsLabel.getLabelType() != null) {
                    if (mallGoodsLabel.getLabelType() == MallGoodsLabelEnums.NEW_LABEL) {
                        //新品，判断商品的创建时间是否大于标签的创建时间
                        if (mallGoodsLabel.getStartTime().before(activity.getCreateTime()) && DateUtil.isIn(new Date(), mallGoodsLabel.getStartTime(), mallGoodsLabel.getEndTime())) {
                            MallProductLabelVO mallProductLabelVO = new MallProductLabelVO();
                            mallProductLabelVO.setLabelType(mallGoodsLabel.getLabelType());
                            mallProductLabelVO.setLabelImage(mallGoodsLabel.getLabelImage());
                            labelList.add(mallProductLabelVO);
                        }
                    } else if (mallGoodsLabel.getLabelType() == MallGoodsLabelEnums.ACTIVITY_LABEL) {
                        //活动
                        if (DateUtil.isIn(new Date(), mallGoodsLabel.getStartTime(), mallGoodsLabel.getEndTime())) {
                            MallProductLabelVO mallProductLabelVO = new MallProductLabelVO();
                            mallProductLabelVO.setLabelType(mallGoodsLabel.getLabelType());
                            mallProductLabelVO.setLabelImage(mallGoodsLabel.getLabelImage());
                            labelList.add(mallProductLabelVO);
                        }
                    }
                }
            }
            activityDTO.setLabelList(labelList);
        }

        return activityDTO;
    }

    public static List<MallActivityExchange> exchangeDistinctOld(List<MallActivityExchange> dataList) {
        // 去重逻辑：type=3 按 linkId 去重；type=1 和 type=2 按 type 去重
        Map<MallExchangeEnum, MallActivityExchange> typeMap = new HashMap<>();
        Map<Long, MallActivityExchange> linkIdMap = new HashMap<>();

        // 用于存储groupId为0的记录
        List<MallActivityExchange> zeroGroupIdList = new ArrayList<>();

        for (MallActivityExchange data : dataList) {
            // 收集groupId为0的记录
            if (data.getGroupId() == 0) {
                zeroGroupIdList.add(data);
            }
        }

        // 如果有groupId为0的记录，优先返回这些记录
        if (!zeroGroupIdList.isEmpty()) {
            return zeroGroupIdList;
        }

        // 如果没有groupId为0的记录，返回groupId最小的一组
        long minGroupId = dataList.stream()
                .mapToLong(MallActivityExchange::getGroupId)
                .filter(groupId -> groupId > 0) // 过滤掉groupId为0的记录
                .min()
                .orElse(Long.MAX_VALUE); // 如果没有有效的groupId，返回最大值

        // 过滤出groupId最小的记录
        List<MallActivityExchange> minGroupIdList = dataList.stream()
                .filter(data -> data.getGroupId() == minGroupId)
                .collect(Collectors.toList());

        for (MallActivityExchange data : minGroupIdList) {
            if (data.getType() == MallExchangeEnum.EQUITY) {
                linkIdMap.putIfAbsent(data.getLinkId(), data);
            } else {
                typeMap.putIfAbsent(data.getType(), data);
            }
        }

        // 合并去重结果
        List<MallActivityExchange> result = new ArrayList<>(linkIdMap.values());
        result.addAll(typeMap.values());
        return result;
    }

    public static List<MallActivityExchange> exchangeDistinct(List<MallActivityExchange> dataList) {
        // 去重逻辑：type=3 按 linkId 去重；type=1 和 type=2 按 type 去重
        Map<MallExchangeEnum, MallActivityExchange> typeMap = new HashMap<>();
        Map<Long, MallActivityExchange> linkIdMap = new HashMap<>();

        for (MallActivityExchange data : dataList) {
            if (data.getType() == MallExchangeEnum.EQUITY) {
                linkIdMap.putIfAbsent(data.getLinkId(), data);
            } else {
                typeMap.putIfAbsent(data.getType(), data);
            }
        }

        List<MallActivityExchange> result = new ArrayList<>(linkIdMap.values());
        result.addAll(typeMap.values());
        return result;
    }

    @Override
    public ActivityDetailV2VO activityDetailV2(UserInfo userInfo, Long id, Long shareTeamId, ActivityTypeEnum exchangeForActivity) {
        MallActivity activity = mallActivityDao.getById(id);
        // 分享购拼团
        MallActivityShare mallActivityShare = null;
        if (Objects.nonNull(shareTeamId)) {
            mallActivityShare = mallActivityShareService.getByTeamId(shareTeamId);
            if (!mallActivityShare.getStatus()) {
                throw new GlobalRunTimeException("活动已结束");
            }
        }
        Assert.notNull(activity, () -> new GlobalRunTimeException("活动已结束"));
        Assert.isTrue(activity.getStatus(), () -> new GlobalRunTimeException("活动已结束"));

        MallProduct product = mallProductService.getById(activity.getProductId());
        ActivityDetailV2VO activityDTO = new ActivityDetailV2VO();
        activityDTO.setActivityId(activity.getId());
        activityDTO.setActivityType(activity.getActivityType());
        activityDTO.setType(product.getType());
        activityDTO.setCategoryId(product.getCategoryId());
        activityDTO.setCoverImages(StrUtil.split(product.getCoverImage(), ","));
        activityDTO.setThumbnail(product.getThumbnail());
        activityDTO.setStatus(activity.getStatus());
        activityDTO.setBuyLimitType(activity.getBuyLimitType());
        MallUserActivitySummary mallUserActivitySummary = mallUserActivitySummaryService.get(userInfo.getId());
        BuyLimitDTO buyLimitDTO = this.convertBuyLimit(activity, mallUserActivitySummary);
        activityDTO.setBuyLimit(buyLimitDTO.getBuyLimit());
        activityDTO.setBuyLimitStr(buyLimitDTO.getBuyLimitStr());
        activityDTO.setBuyLimitType(activity.getBuyLimitType());
        activityDTO.setStartTime(activity.getStartTime());
        activityDTO.setProductCode(product.getProductCode());
        activityDTO.setProductName(product.getProductName());
        activityDTO.setProductDetail(StrUtil.split(product.getProductDetail(), ","));
        activityDTO.setAllReadyStart(DateTime.now().after(activity.getStartTime()));
        activityDTO.setAllowedShoppingCoupons(product.isAllowedShoppingCoupons());
        if (Objects.nonNull(product.getAttributeId())) {
            // 属性
            MallProductAttribute productAttribute = mallProductAttributeDao.getById(product.getAttributeId());
            if (StringUtils.isNotBlank(productAttribute.getAttributeDetail())) {
                List<AttributeDetailDTO> attributeDetailDTOS = JSONArray.parseArray(productAttribute.getAttributeDetail(), AttributeDetailDTO.class);
                activityDTO.setAttributeDetailDTOList(attributeDetailDTOS);
                activityDTO.setAttributeName(productAttribute.getAttributeName());
            }
        }
        UserCreatorInfo dao = userCreatorInfoDao.getById(activity.getDaoId());
        activityDTO.setDaoName(dao.getDaoName());
        activityDTO.setDaoId(dao.getId());
        activityDTO.setIsDao(dao.getStatus());
        activityDTO.setDaoImg(dao.getCreatorAvatarImg());

        List<MallActivitySpecs> mallActivitySpecs = mallActivitySpecsDao.getByActivityId(activity.getId());
        if (Objects.nonNull(mallActivityShare)) {
            // 存在拼团价
            List<MallActivityShareSpecs> mallActivityShareSpecs = mallActivityShareSpecsService.getMallActivityShareSpecs(mallActivityShare.getId());
            Map<Long, BigDecimal> mallActivityShareSpecsMap = mallActivityShareSpecs.stream().collect(Collectors.toMap(MallActivityShareSpecs::getActivitySpecsId, MallActivityShareSpecs::getSalesPrice, (value1, value2) -> value1));
            for (MallActivitySpecs mallActivitySpec : mallActivitySpecs) {
                BigDecimal shareSalesPrice = mallActivityShareSpecsMap.get(mallActivitySpec.getId());
                if (Objects.nonNull(shareSalesPrice) && BigDecimalUtils.greaterZero(shareSalesPrice)) {
                    mallActivitySpec.setSalesPrice(shareSalesPrice);
                }
            }

        }
        if (activityDTO.getActivityType() == ActivityTypeEnum.SALES) {
            String salesPrice = mallActivitySpecs.stream().map(MallActivitySpecs::getSalesPrice).min(BigDecimal::compareTo).get().toPlainString();
            activityDTO.setMinPrice(salesPrice);
            activityDTO.setMaxPrice(mallActivitySpecs.stream().map(MallActivitySpecs::getSalesPrice).max(BigDecimal::compareTo).get().toPlainString());
            if (mallActivitySpecs.size() > 1) {
                salesPrice += "起";
            }
            activityDTO.setSalesPrice(salesPrice);
        }
        List<ActivitySpecsVO> specsDTOS = Lists.newArrayList();
        int sumUsableCount = 0;
        int sumCount = 0;
        for (MallActivitySpecs mallActivitySpec : mallActivitySpecs) {
            ActivitySpecsVO activitySpecsDTO = new ActivitySpecsVO();
            activitySpecsDTO.setActivitySpecsId(mallActivitySpec.getId());
            MallProductSpecs specs = mallProductSpecsDao.getById(mallActivitySpec.getSpecsId());
            if (StringUtils.isNotBlank(specs.getApiProductElementInfo())) {
                ElementInfoDTO elementInfoDTO = JSON.parseObject(specs.getApiProductElementInfo(), ElementInfoDTO.class);
                activitySpecsDTO.setElementInfoDTO(elementInfoDTO);
            }
            activitySpecsDTO.setThumbnail(specs.getThumbnail());
            activitySpecsDTO.setSpecsName(specs.getSpecsName());
            activitySpecsDTO.setSpecsCode(specs.getSpecsCode());
            activitySpecsDTO.setSalesPrice(mallActivitySpec.getSalesPrice().toPlainString());
            activitySpecsDTO.setUsableCount(mallActivitySpec.getUsableStockCount());
            sumUsableCount += mallActivitySpec.getUsableStockCount();
            sumCount += mallActivitySpec.getSumStockCount();
            specsDTOS.add(activitySpecsDTO);
        }
        activityDTO.setSumCount(sumCount);
        activityDTO.setStockEnough(sumUsableCount > 0);
        activityDTO.setActivitySpecs(specsDTOS);
        List<MallActivityExchange> exchanges = mallActivityExchangeDao.getByActivityId(activity.getId());
        // 使用TreeMap按groupId分组并自动排序
        Map<Long, List<MallActivityExchange>> groupedExchanges = exchanges.stream()
                .collect(Collectors.groupingBy(MallActivityExchange::getGroupId, TreeMap::new, Collectors.toList()));
        List<ActivityExchangeV2VO> exchangeDTOS = Lists.newArrayList();

        Integer userBuyCount = mallOrderProductService.getUserBuyCountByUserIdAndActivityId(userInfo.getId(), activity.getId());
        if (BeanUtil.isNotEmpty(activity) && activity.getActivityType().equals(ActivityTypeEnum.EXCHANGE)) {
            //exchanges 单位积分、权益道具、nft
            if (userBuyCount.equals(activityDTO.getBuyLimit())) {
                activityDTO.setExchangePropEnough(Boolean.FALSE);
            }
            //判断是否已经达到兑换上限
            if (activity.getBuyLimitType() == MallBuyLimitTypeEnum.DYNAMIC) {
                if (userBuyCount.equals(buyLimitDTO.getBuyLimit())) {
                    activityDTO.setExchangeLimit(Boolean.TRUE);
                }
            }else{
                if (userBuyCount.equals(activityDTO.getBuyLimit())) {
                    activityDTO.setExchangeLimit(Boolean.TRUE);
                }
            }
        }
        UserAssets userAssets = userAssetsDao.getByUserIdAndCoinId(userInfo.getId(), CoinCategoryEnum.INTEGRAL.getCode());
        BigDecimal maxTotalNumIn = BigDecimal.valueOf(activityDTO.getBuyLimit());
        BigDecimal maxTotalNumEq = BigDecimal.valueOf(activityDTO.getBuyLimit());
        BigDecimal maxTotalNumNft = BigDecimal.valueOf(activityDTO.getBuyLimit());

        for (Map.Entry<Long, List<MallActivityExchange>> longListEntry : groupedExchanges.entrySet()) {
            ActivityExchangeV2VO activityExchangeVO = new ActivityExchangeV2VO();
            List<MallActivityExchange> mallActivityExchangeList = longListEntry.getValue();
            // 去重操作
            // 场景一：获取4条数据
            List<MallActivityExchange> distinctList = exchangeDistinct(mallActivityExchangeList);


            Long groupId = longListEntry.getKey();
            activityExchangeVO.setGroupId(String.valueOf(groupId));
            List<ActivityExchangeV2VO.ActivityExchangeDTO> activityExchangeDTOList = new ArrayList<>();
            BigDecimal maxTotalNum = BigDecimal.ZERO;
            Boolean exchangePropEnough = true;
            List<BigDecimal> maxTotalNumList = new ArrayList<>();
            for (MallActivityExchange exchange : distinctList) {
                int costNum = exchange.getCostNum();

                ActivityExchangeV2VO.ActivityExchangeDTO activitySpecsExchangeDTO = new ActivityExchangeV2VO.ActivityExchangeDTO();
                activitySpecsExchangeDTO.setType(1);
                activitySpecsExchangeDTO.setExchangeType(exchange.getType());
                activitySpecsExchangeDTO.setName(exchange.getLinkName());
                activitySpecsExchangeDTO.setLinkImage(exchange.getLinkImage());
                BigDecimal buyLimit = BigDecimal.valueOf(activityDTO.getBuyLimit());
                if (activity.getBuyLimitType() == MallBuyLimitTypeEnum.DYNAMIC) {
                    buyLimit = BigDecimal.valueOf(buyLimitDTO.getBuyLimit());
                }
                switch (exchange.getType()) {
                    case INTEGRAL:
                        if (ObjectUtil.isNotNull(userInfo)) {
                            activitySpecsExchangeDTO.setHoldCount(userAssets == null ? "0" : userAssets.getTokenNum().toPlainString());
                        } else {
                            activitySpecsExchangeDTO.setHoldCount("0");
                        }
                        Integer usableStockCount = mallActivitySpecs.get(0).getUsableStockCount();
                        if (mallActivitySpecs.get(0).getUsableStockCount() < 0) {
                            activityDTO.setExchangePropEnough(Boolean.FALSE);
                            exchangePropEnough = Boolean.FALSE;
                        }
                        //用户上限还可以买多少个 还需要判断消耗道具是否充足
                        if (ObjectUtil.isNotNull(exchangeForActivity) && exchangeForActivity.equals(ActivityTypeEnum.EXCHANGE)) {
                                maxTotalNumIn = (userAssets == null ? BigDecimal.ZERO : userAssets.getTokenNum()).divide(BigDecimal.valueOf(costNum), 0, BigDecimal.ROUND_DOWN);
                                activityDTO.setMaxTotalNum(buyLimit.subtract(BigDecimal.valueOf(userBuyCount)).min(maxTotalNumIn));
                                maxTotalNum = buyLimit.subtract(BigDecimal.valueOf(userBuyCount)).min(maxTotalNumIn);
                                activityDTO.setExchangePropEnough(Boolean.TRUE);
                                exchangePropEnough = Boolean.TRUE;
                                if (activityDTO.getMaxTotalNum().compareTo(BigDecimal.ZERO) <= 0) {
                                    activityDTO.setExchangePropEnough(Boolean.FALSE);
                                    exchangePropEnough = Boolean.FALSE;
                                }
                        }
                        break;
                    case EQUITY:
                        if (ObjectUtil.isNotNull(userInfo)) {
                            //这里没拿到权益道具数量
                            Integer count = userEquityPropsDao.getHavingCountByUserId(exchange.getLinkId(), userInfo.getId());
                            activitySpecsExchangeDTO.setHoldCount(count.toString());
                        } else {
                            activitySpecsExchangeDTO.setHoldCount("0");
                        }
                        if (ObjectUtil.isNotNull(exchangeForActivity) && exchangeForActivity.equals(ActivityTypeEnum.EXCHANGE)) {
                            //单位商品的道具消耗数量 equityCostNum
                            BigDecimal tokenNum = new BigDecimal(activitySpecsExchangeDTO.getHoldCount());
                            maxTotalNumEq = tokenNum.divide(BigDecimal.valueOf(costNum), 0, BigDecimal.ROUND_DOWN);
                            //用户持有的权益道具数量
                            activityDTO.setMaxTotalNum(buyLimit.subtract(BigDecimal.valueOf(userBuyCount)).min(maxTotalNumEq));
                            maxTotalNum = buyLimit.subtract(BigDecimal.valueOf(userBuyCount)).min(maxTotalNumEq);
                            activityDTO.setExchangePropEnough(Boolean.TRUE);
                            exchangePropEnough = Boolean.TRUE;
                            if (activityDTO.getMaxTotalNum().compareTo(BigDecimal.ZERO) <= 0) {
                                activityDTO.setExchangePropEnough(Boolean.FALSE);
                                exchangePropEnough = Boolean.FALSE;
                            }
                        }
                        break;
                    case NFT:
                        if (ObjectUtil.isNotNull(userInfo)) {
                            //nft数量
                            Integer count = userCollectionDao.getCountByCollectionNotConsignId(exchange.getLinkId(), userInfo.getId());
                            activitySpecsExchangeDTO.setHoldCount(count.toString());
                        } else {
                            activitySpecsExchangeDTO.setHoldCount("0");
                        }
                        if (ObjectUtil.isNotNull(exchangeForActivity) && exchangeForActivity.equals(ActivityTypeEnum.EXCHANGE)) {
                            BigDecimal tokenNum = new BigDecimal(activitySpecsExchangeDTO.getHoldCount());
                            maxTotalNumNft = tokenNum.divide(BigDecimal.valueOf(costNum), 0, BigDecimal.ROUND_DOWN);
                            //用户持有的权益道具数量
                            activityDTO.setMaxTotalNum(buyLimit.subtract(BigDecimal.valueOf(userBuyCount)).min(maxTotalNumNft));
                            maxTotalNum = buyLimit.subtract(BigDecimal.valueOf(userBuyCount)).min(maxTotalNumNft);
                            activityDTO.setExchangePropEnough(Boolean.TRUE);
                            exchangePropEnough = Boolean.TRUE;
                            if (activityDTO.getMaxTotalNum().compareTo(BigDecimal.ZERO) <= 0) {
                                activityDTO.setExchangePropEnough(Boolean.FALSE);
                                exchangePropEnough = Boolean.FALSE;
                            }
                        }
                        break;
                }
                activitySpecsExchangeDTO.setCount(exchange.getCostNum());
                //用户上限还可以兑换几个 添加默认值
                log.debug("最大可兑换数量为：", activityDTO.getMaxTotalNum());
                if (Objects.isNull(activityDTO.getMaxTotalNum()) || activityDTO.getMaxTotalNum().compareTo(BigDecimal.ZERO) <= 0) {
                    log.debug("覆盖了最大可兑换数量：", activityDTO.getMaxTotalNum());
                    activityDTO.setMaxTotalNum(BigDecimal.ZERO);
                    maxTotalNum = BigDecimal.ZERO;
                    activityDTO.setExchangePropEnough(Boolean.FALSE);
                    exchangePropEnough = Boolean.FALSE;
                }
                activityExchangeDTOList.add(activitySpecsExchangeDTO);
                maxTotalNumList.add(maxTotalNum);
            }
            boolean checkExchange = true;
            for (ActivityExchangeV2VO.ActivityExchangeDTO exchangeDTO : activityExchangeDTOList) {
                if (NumberUtil.isGreater(BigDecimal.valueOf(exchangeDTO.getCount()), new BigDecimal(exchangeDTO.getHoldCount()))) {
                    checkExchange = false;
                    break;
                }
            }
            if (activity.getBuyLimitType() == MallBuyLimitTypeEnum.DYNAMIC) {
                if (checkExchange && buyLimitDTO.getBuyLimit() <= 0) {
                    checkExchange = false;
                }
            }
            activityExchangeVO.setActivityExchangeDTOList(activityExchangeDTOList);
            activityExchangeVO.setCheckExchange(checkExchange);
            BigDecimal maxTotalNumNew = Collections.min(maxTotalNumList);
            activityExchangeVO.setMaxTotalNum(maxTotalNumNew);
            activityExchangeVO.setExchangePropEnough(exchangePropEnough);
            exchangeDTOS.add(activityExchangeVO);
        }

        //积分 权益道具 nft 三者取最小
        activityDTO.setMaxTotalNum(maxTotalNumIn.min(maxTotalNumEq).min(maxTotalNumNft));
        if (ObjectUtil.isNotNull(userInfo)) {
            if (activity.getParticipants() == ParticipantsEnum.APPOINT) {
                ActivityExchangeV2VO.ActivityExchangeDTO activitySpecsExchangeDTO = new ActivityExchangeV2VO.ActivityExchangeDTO();
                activitySpecsExchangeDTO.setType(2);
                DigitalCollection collection = digitalCollectionDao.getById(activity.getCollectionId());
                activitySpecsExchangeDTO.setName(collection.getFirstTitle());
                activitySpecsExchangeDTO.setCount(1);
                activitySpecsExchangeDTO.setHoldCount(String.valueOf(userCollectionDao.getByUserIdAndCollectionIdCount(userInfo.getId(), activity.getCollectionId())));
                activitySpecsExchangeDTO.setLinkImage(collection.getCreationContent());
                for (ActivityExchangeV2VO exchangeDTO : exchangeDTOS) {
                    Boolean checkExchange = false;
                    if(exchangeDTO.getCheckExchange() && !NumberUtil.isGreater(BigDecimal.valueOf(activitySpecsExchangeDTO.getCount()), new BigDecimal(activitySpecsExchangeDTO.getHoldCount()))){
                        checkExchange = true;
                    }
                    exchangeDTO.setCheckExchange(checkExchange);
                    exchangeDTO.getActivityExchangeDTOList().add(activitySpecsExchangeDTO);
                }
            }
        }
        //如果有一组满足就是true
        boolean checkExchange = exchangeDTOS != null && exchangeDTOS.stream()
                .allMatch(group -> {
                    List<ActivityExchangeV2VO.ActivityExchangeDTO> dtoList = group.getActivityExchangeDTOList();
                    return dtoList == null || dtoList.stream()
                            .noneMatch(exchangeDTO -> {
                                BigDecimal holdCountValue = StringUtils.isNotBlank(exchangeDTO.getHoldCount())
                                        ? new BigDecimal(exchangeDTO.getHoldCount())
                                        : BigDecimal.ZERO;

                                return NumberUtil.isGreater(
                                        BigDecimal.valueOf(exchangeDTO.getCount()),
                                        holdCountValue
                                );
                            });
                });
        if (activity.getBuyLimitType() == MallBuyLimitTypeEnum.DYNAMIC) {
            if (checkExchange && buyLimitDTO.getBuyLimit() <= 0) {
                checkExchange = false;
            }
        }
        activityDTO.setCheckExchange(checkExchange);
        activityDTO.setActivityExchanges(exchangeDTOS);
        // 判断是否有拼团活动
        Boolean hasShare = mallActivityShareService.hasShareByActivityId(id);
        activityDTO.setIsHasActivityShare(hasShare);
        //判断是否有会员优先抢的权益
        MallMemberCheckHasPreemptionDTO checkHasPreemptionDTO = mallMemberEquityService.checkHasPreemption(userInfo, mallActivitySpecs.get(0).getId());
        //优先购泡判断条件 1.有优先购的权限，并且是活动时间之前（正常活动时间倒推至权益设置提前时间的中间）
        if (Objects.nonNull(checkHasPreemptionDTO)) {
            //判断时间现在是否能为优先购时间
            DateTime checkTime = DateUtil.offsetMinute(activity.getStartTime(), -checkHasPreemptionDTO.getPrioritizeTheLeadTime());
            if (DateUtil.isIn(DateTime.now(), checkTime, activity.getStartTime())) {
                activityDTO.setIsHasPreemption(Boolean.TRUE);
                activityDTO.setAllReadyStart(DateTime.now().after(checkTime));
            }
            activityDTO.setStartTime(checkTime);
        }
        //查询商品绑定的标签
        List<MallGoodsLabel> mallGoodsLabelList = mallGoodsLabelDao.productDetailsGetLabel(activity.getId());
        if (!CollectionUtils.isEmpty(mallGoodsLabelList)) {
            List<MallProductLabelVO> labelList = new ArrayList<>();
            for (MallGoodsLabel mallGoodsLabel : mallGoodsLabelList) {
                if (mallGoodsLabel.getLabelType() != null) {
                    if (mallGoodsLabel.getLabelType() == MallGoodsLabelEnums.NEW_LABEL) {
                        //新品，判断商品的创建时间是否大于标签的创建时间
                        if (mallGoodsLabel.getStartTime().before(activity.getCreateTime()) && DateUtil.isIn(new Date(), mallGoodsLabel.getStartTime(), mallGoodsLabel.getEndTime())) {
                            MallProductLabelVO mallProductLabelVO = new MallProductLabelVO();
                            mallProductLabelVO.setLabelType(mallGoodsLabel.getLabelType());
                            mallProductLabelVO.setLabelImage(mallGoodsLabel.getLabelImage());
                            labelList.add(mallProductLabelVO);
                        }
                    } else if (mallGoodsLabel.getLabelType() == MallGoodsLabelEnums.ACTIVITY_LABEL) {
                        //活动
                        if (DateUtil.isIn(new Date(), mallGoodsLabel.getStartTime(), mallGoodsLabel.getEndTime())) {
                            MallProductLabelVO mallProductLabelVO = new MallProductLabelVO();
                            mallProductLabelVO.setLabelType(mallGoodsLabel.getLabelType());
                            mallProductLabelVO.setLabelImage(mallGoodsLabel.getLabelImage());
                            labelList.add(mallProductLabelVO);
                        }
                    }
                }
            }
            activityDTO.setLabelList(labelList);
        }

        return activityDTO;
    }

    @Override
    public void activityApproval(Long id, Boolean pass, String remark) {
        MallActivity activity = mallActivityDao.getById(id);
        Assert.notNull(activity, () -> new GlobalRunTimeException("活动不存在"));
        Assert.isTrue(activity.getApprovalStatus() == ApprovalStatusEnum.APPROVAL, () -> new GlobalRunTimeException("活动不在待审核状态"));
        if (pass) {
            activity.setApprovalStatus(ApprovalStatusEnum.PASS);
        } else {
            activity.setApprovalStatus(ApprovalStatusEnum.REFUSE);
            activity.setRemark(remark);
        }
        activity.updateById();
    }

    @Override
    public IPage<HotSaleActivityPageVO> hotSaleProductPage(String productName, Integer hotSaleSort, Page mp) {
        IPage<HotSaleActivityPageVO> page = mallActivityDao.hotSaleProductPage(productName, hotSaleSort, mp);
        for (HotSaleActivityPageVO record : page.getRecords()) {
            if (record.getSpecsCount() > 1) {
                record.setSalesPrice(record.getSalesPrice() + "起");
            }
            if (StrUtil.isNotBlank(record.getCoverImage())) {
                record.setCoverImage(StrUtil.split(record.getCoverImage(), ",").get(0));
            }
            //判断标签
            if (record.getLabelType() != null) {
                if (record.getLabelType() == MallGoodsLabelEnums.NEW_LABEL) {
                    //新品，判断商品的创建时间是否大于标签的创建时间
                    if (record.getLabelStartTime().after(record.getCreateTime()) || !DateUtil.isIn(new Date(), record.getLabelStartTime(), record.getLabelEndTime())) {
                        record.setLabelImage(null);
                    }
                } else if (record.getLabelType() == MallGoodsLabelEnums.ACTIVITY_LABEL) {
                    //活动
                    if (!DateUtil.isIn(new Date(), record.getLabelStartTime(), record.getLabelEndTime())) {
                        record.setLabelImage(null);
                    }
                }
            }
        }
        return page;
    }

    /**
     * 好物优选列表
     *
     * @param page
     * @return
     */
    @Override
    public Page<PreferenceActivityDTO> preferenceProductPage(Page page) {
        Page<PreferenceActivityDTO> preferenceActivityDTOPage = mallActivityDao.preferenceProductPage(page);
        for (PreferenceActivityDTO record : preferenceActivityDTOPage.getRecords()) {
            if (record.getSpecsCount() > 1) {
                record.setSalesPrice(record.getSalesPrice() + "起");
            }
            if (StrUtil.isNotBlank(record.getCoverImage())) {
                record.setCoverImage(StrUtil.split(record.getCoverImage(), ",").get(0));
            }
            //判断标签
            if (record.getLabelType() != null) {
                if (record.getLabelType() == MallGoodsLabelEnums.NEW_LABEL) {
                    //新品，判断商品的创建时间是否大于标签的创建时间
                    if (record.getLabelStartTime().after(record.getCreateTime()) || !DateUtil.isIn(new Date(), record.getLabelStartTime(), record.getLabelEndTime())) {
                        record.setLabelImage(null);
                    }
                } else if (record.getLabelType() == MallGoodsLabelEnums.ACTIVITY_LABEL) {
                    //活动
                    if (!DateUtil.isIn(new Date(), record.getLabelStartTime(), record.getLabelEndTime())) {
                        record.setLabelImage(null);
                    }
                }
            }
        }
        return preferenceActivityDTOPage;
    }

    @Override
    public IPage<BargainPriceProductPageVO> bargainPriceProductPage(String productName, Integer bargainPriceSort, Page mp, Boolean isSaas) {
        String restrictDaoIdStr = staticDataDao.getByType("restrict_dao_id").getValue();
        Long restrictDaoId = Long.valueOf(restrictDaoIdStr);
        Integer isShow = MallActivityShowChannelEnum.SHOW_DAO.getCode();
        if (isSaas) {
            isShow = MallActivityShowChannelEnum.SHOW_SAAS_DAO.getCode();
        }
        IPage<BargainPriceProductPageVO> page = mallActivityDao.bargainPriceProductPage(productName, bargainPriceSort, mp, isShow);
        for (BargainPriceProductPageVO record : page.getRecords()) {
            if (record.getSpecsCount() > 1) {
                record.setSalesPrice(record.getSalesPrice() + "起");
            }
            record.setCollectionName(record.getCollectionName() + "专享");
            if (StrUtil.isNotBlank(record.getCoverImage())) {
                record.setCoverImage(StrUtil.split(record.getCoverImage(), ",").get(0));
            }
            //判断标签
            if (record.getLabelType() != null) {
                if (record.getLabelType() == MallGoodsLabelEnums.NEW_LABEL) {
                    //新品，判断商品的创建时间是否大于标签的创建时间
                    if (record.getLabelStartTime().after(record.getCreateTime()) || !DateUtil.isIn(new Date(), record.getLabelStartTime(), record.getLabelEndTime())) {
                        record.setLabelImage(null);
                    }
                } else if (record.getLabelType() == MallGoodsLabelEnums.ACTIVITY_LABEL) {
                    //活动
                    if (!DateUtil.isIn(new Date(), record.getLabelStartTime(), record.getLabelEndTime())) {
                        record.setLabelImage(null);
                    }
                }
            }
        }
        return page;
    }

    @Override
    public IPage<CategoryProductPageVO> categoryProductPage(Long id, String productName, Integer sort, Boolean isVirtual, Page mp, Boolean isSaas, Boolean showMiniMall) {
        String restrictDaoIdStr = staticDataDao.getByType("restrict_dao_id").getValue();
        Long restrictDaoId = Long.valueOf(restrictDaoIdStr);
        Integer isShow = MallActivityShowChannelEnum.SHOW_DAO_NONO.getCode();
        if (isSaas) {
            isShow = MallActivityShowChannelEnum.SHOW_SAAS_DAO.getCode();
        }
        IPage<CategoryProductPageVO> page = mallActivityDao.categoryProductPage(mp, id, productName, sort, isVirtual, isShow, showMiniMall);
        for (CategoryProductPageVO record : page.getRecords()) {
            if (record.getSpecsCount() > 1) {
                record.setSalesPrice(record.getSalesPrice() + "起");
            }
            if (StrUtil.isNotBlank(record.getCoverImage())) {
                record.setCoverImage(StrUtil.split(record.getCoverImage(), ",").get(0));
            }
            //判断标签
            if (record.getLabelType() != null) {
                if (record.getLabelType() == MallGoodsLabelEnums.NEW_LABEL) {
                    //新品，判断商品的创建时间是否大于标签的创建时间
                    if (record.getLabelStartTime().after(record.getCreateTime()) || !DateUtil.isIn(new Date(), record.getLabelStartTime(), record.getLabelEndTime())) {
                        record.setLabelImage(null);
                    }
                } else if (record.getLabelType() == MallGoodsLabelEnums.ACTIVITY_LABEL) {
                    //活动
                    if (!DateUtil.isIn(new Date(), record.getLabelStartTime(), record.getLabelEndTime())) {
                        record.setLabelImage(null);
                    }
                }
            }
        }
        return page;
    }


    @Override
    public IPage<CategoryProductPageVO> miniMallCategoryProductPage(Long id, String productName, Integer sort, Boolean isVirtual, Page mp, Boolean isSaas, Boolean showMiniMall) {
        IPage<CategoryProductPageVO> page = mallActivityDao.categoryProductPage(mp, id, productName, sort, isVirtual, null, showMiniMall);
        for (CategoryProductPageVO record : page.getRecords()) {
            if (record.getSpecsCount() > 1) {
                record.setSalesPrice(record.getSalesPrice() + "起");
            }
            if (StrUtil.isNotBlank(record.getCoverImage())) {
                record.setCoverImage(StrUtil.split(record.getCoverImage(), ",").get(0));
            }
        }
        return page;
    }

    @Override
    public IPage<AdminSalesPageVO> getSalesPage(Page page) {
        return mallActivityDao.getSalesPage(page);
    }

    /**
     * 强制下架
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void offShelf(Long id) {
        MallActivity activity = getActivity(id);
        Assert.isTrue(activity.getStatus(), () -> new GlobalRunTimeException("活动未上架"));
        activity.setStatus(false);
        activity.updateById();
        mallProductService.offShelf(id);
        mallActivityShareService.disableByActivityId(id);
    }

    /**
     * 修改活动商品库存
     *
     * @param mallActivityStockUpdateVO
     * @return
     */
    @Override
    public void updateMallActivityStock(MallActivityStockUpdateVO mallActivityStockUpdateVO) {
        MallActivity activity = getActivity(mallActivityStockUpdateVO.getActivityId());
        Assert.notNull(activity, () -> new GlobalRunTimeException("活动不存在"));
        Assert.isTrue(activity.getStatus(), () -> new GlobalRunTimeException("活动未上架"));
        // 活动商品规格
        MallActivitySpecs mallActivitySpecs = mallActivitySpecsService.getById(mallActivityStockUpdateVO.getId());
        Assert.notNull(mallActivitySpecs, () -> new GlobalRunTimeException("活动商品规格不存在"));
        // 新可用库存
        Integer newUsableStockCount = mallActivityStockUpdateVO.getOutPutAndInPutOfWarehouseNum() + mallActivitySpecs.getUsableStockCount();
        // 出入库库存不能大于可用库存
        Assert.isFalse(newUsableStockCount < 0, () -> new GlobalRunTimeException("出库存不能大于可用库存"));
        // 出入库
        Boolean result = mallActivitySpecsService.updateUsableStockCountById(mallActivitySpecs.getId(), mallActivityStockUpdateVO.getOutPutAndInPutOfWarehouseNum());
        if (!result) {
            throw new GlobalRunTimeException("出库存不能大于可用库存");
        }
    }

    /**
     * 修改活动商品渠道
     *
     * @param mallActivityStockUpdateVO
     */
    @Override
    public void updateShowChannel(MallActivityUpdateShowChannelVO mallActivityStockUpdateVO) {
        List<Long> showChannelList = mallActivityStockUpdateVO.getShowChannelList();
        Boolean showMiniMall = mallActivityStockUpdateVO.getShowMiniMall();
        if (showChannelList.size() <= 0 && Objects.isNull(showMiniMall)) {
            throw new GlobalRunTimeException("活动商品最少有一个展示渠道");
        }
        //仅选了小程序
        if (CollectionUtils.isEmpty(showChannelList) && showMiniMall) {
            mallActivityDao.updateShowChannel(mallActivityStockUpdateVO.getActivityId(), "", Boolean.TRUE);
        } else if (!CollectionUtils.isEmpty(showChannelList) && showMiniMall) {
            //选了小程序又选了其他的
            mallActivityDao.updateShowChannel(mallActivityStockUpdateVO.getActivityId(), JSON.toJSONString(showChannelList), Boolean.TRUE);
        } else {
            //仅选了其他的
            mallActivityDao.updateShowChannel(mallActivityStockUpdateVO.getActivityId(), JSON.toJSONString(showChannelList), Boolean.FALSE);
        }

    }

    @Override
    public void updateMallActivitySalesPrice(MallActivitySalesPriceUpdateVO mallActivitySalesPriceUpdateVO) {
        MallActivity activity = getActivity(mallActivitySalesPriceUpdateVO.getActivityId());
        Assert.notNull(activity, () -> new GlobalRunTimeException("活动不存在"));
        Assert.isTrue(activity.getStatus(), () -> new GlobalRunTimeException("活动未上架"));
        // 活动商品规格
        MallActivitySpecs mallActivitySpecs = mallActivitySpecsService.getById(mallActivitySalesPriceUpdateVO.getId());
        Assert.notNull(mallActivitySpecs, () -> new GlobalRunTimeException("活动商品规格不存在"));
        // 销售价格
        BigDecimal costPrice = BigDecimalUtils.add(mallActivitySpecs.getCostPrice(), mallActivitySpecs.getActivityCostPrice(), mallActivitySpecs.getReservePrice());
        Assert.isFalse(NumberUtil.isGreaterOrEqual(costPrice, mallActivitySalesPriceUpdateVO.getSalesPrice()), () -> new GlobalRunTimeException("销售价不能小于成本价"));
        BigDecimal profit = BigDecimalUtils.subtract(mallActivitySalesPriceUpdateVO.getSalesPrice(), costPrice);
        mallActivitySpecsService.updateMallActivitySalesPriceById(mallActivitySalesPriceUpdateVO.getId(), mallActivitySalesPriceUpdateVO.getSalesPrice(), profit);
    }

    @Override
    public boolean checkProductActivity(Long productId) {
        return mallActivityDao.checkProductActivity(productId);
    }

    @Override
    public IPage<ActivityPageVO> allCategories(Long daoId, Long categoryId, ActivityTypeEnum activityType, ProductTypeEnum productType, String productName, Page mp, Integer sort, Boolean isMiniMall) {
        IPage<ActivityPageVO> activityPage = mallActivityDao.allCategories(daoId, categoryId, activityType, productType, productName, mp, sort, isMiniMall);
        for (ActivityPageVO record : activityPage.getRecords()) {
            if (record.getSpecsCount() > 1) {
                record.setSalesPrice(record.getSalesPrice() + "起");
            }
            if (StrUtil.isNotBlank(record.getCoverImage())) {
                record.setCoverImage(StrUtil.split(record.getCoverImage(), ",").get(0));
            }
            if (record.getActivityType() == ActivityTypeEnum.EXCHANGE) {
                List<ActivityExchangeVO> exchangeDTOS = Lists.newArrayList();
                List<MallActivityExchange> exchanges = mallActivityExchangeDao.getByActivityId(record.getActivityId());
                for (MallActivityExchange exchange : exchanges) {
                    ActivityExchangeVO activitySpecsExchangeDTO = new ActivityExchangeVO();
                    activitySpecsExchangeDTO.setType(1);
                    activitySpecsExchangeDTO.setName(exchange.getLinkName());
                    activitySpecsExchangeDTO.setCount(exchange.getCostNum());
                    activitySpecsExchangeDTO.setLinkImage(exchange.getLinkImage());
                    exchangeDTOS.add(activitySpecsExchangeDTO);
                }
                record.setActivityExchanges(exchangeDTOS);
            }
            //判断标签
            if (record.getLabelType() != null) {
                if (record.getLabelType() == MallGoodsLabelEnums.NEW_LABEL) {
                    //新品，判断商品的创建时间是否大于标签的创建时间
                    if (record.getLabelStartTime().after(record.getCreateTime()) || !DateUtil.isIn(new Date(), record.getLabelStartTime(), record.getLabelEndTime())) {
                        record.setLabelImage(null);
                    }
                } else if (record.getLabelType() == MallGoodsLabelEnums.ACTIVITY_LABEL) {
                    //活动
                    if (!DateUtil.isIn(new Date(), record.getLabelStartTime(), record.getLabelEndTime())) {
                        record.setLabelImage(null);
                    }
                }
            }
        }
        return activityPage;
    }

    @Override
    public IPage<AdminSalesPageVO> getProductPage(Page mp) {
        return mallActivityDao.getProductPage(mp);
    }

    /**
     * 校验购物车商品是否已失效
     *
     * @param activityId
     * @param activitySpecsId
     * @return
     */
    @Override
    public CartExpiredEnum checkCartExpired(Long activityId, Long activitySpecsId, WxMiniUserInfo wxMiniUserInfo, Integer buyCount) {
        //获取活动商品信息
        MallActivity mallActivity = getCanBuy(activityId);
        if (Objects.isNull(mallActivity)) {
            // 商品已下架
            return CartExpiredEnum.NO_LONGER_AVAILABLE;
        }
        // 获取活动商品规格信息
        MallActivitySpecs mallActivitySpecs = mallActivitySpecsService.getById(activitySpecsId);
        if (Objects.isNull(mallActivitySpecs)) {
            // 商品已下架
            return CartExpiredEnum.NO_LONGER_AVAILABLE;
        }
        if (mallActivitySpecs.getUsableStockCount() <= 0) {
            // 商品已售罄
            return CartExpiredEnum.SOLD_OUT;
        }
        if (mallActivitySpecs.getUsableStockCount() - buyCount <= 0) {
            // 商品库存不足
            return CartExpiredEnum.INSUFFICIENT_STOCK;
        }

        //校验购买上限(小程序订单)
        Integer userBuyCount = mallOrderProductService.getMiniUserBuyCountByUserIdAndActivityId(wxMiniUserInfo.getId(), mallActivity.getId());
        if (userBuyCount + buyCount >= mallActivity.getBuyLimit()) {
            // 商品库存不足
            return CartExpiredEnum.THE_PURCHASE_LIMIT_HAS_BEEN_EXCEEDED;
        }

        if (mallActivity.getStartTime().after(new Date())) {
            // 商品未开始
            return CartExpiredEnum.NOT_ELIGIBLE_FOR_PURCHASE;
        }

        //校验参与对象
        if (mallActivity.getParticipants() == ParticipantsEnum.APPOINT) {
            //如果是指定NFT
            Long collectionId = mallActivity.getCollectionId();
            //判断id是否为空
            Assert.notNull(collectionId, () -> new GlobalRunTimeException(ErrorCode.COLLECTION_NOT_FOUND));
            //判断id是否为0
            Assert.isFalse(collectionId == 0L, () -> new GlobalRunTimeException(ErrorCode.MALL_THE_PRODUCT_IS_NO_LONGER_AVAILABLE));
            if (userCollectionService.getIsContainsAndIsHoldAndIsOpenAndOnConsignByCollectionId(collectionId, wxMiniUserInfo.getUserId()) <= 0) {
                return CartExpiredEnum.NOT_ELIGIBLE_FOR_PURCHASE;
            }
        }
        return CartExpiredEnum.NORMAL;
    }


    /**
     * 获取优惠券中的活动商品列表
     *
     * @param ids
     * @param toMp
     * @return
     */
    @Override
    public Page<ActivityCouponsProductDTO> getActivityCouponsProductDTOPage(List<Long> ids, Page toMp, Integer status) {
        return mallActivityDao.getActivityCouponsProductDTOPage(toMp, ids, status);
    }

    /**
     * 获取优惠券中的活动商品列表
     *
     * @param ids
     * @return
     */
    @Override
    public List<ActivityCouponsProductDTO> getActivityCouponsProductDTOList(List<Long> ids) {
        List<ActivityCouponsProductDTO> activityCouponsProductDTOList = mallActivityDao.getActivityCouponsProductDTOList(ids);
        for (ActivityCouponsProductDTO activityCouponsProductDTO : activityCouponsProductDTOList) {
            if (StrUtil.isNotBlank(activityCouponsProductDTO.getCoverImage())) {
                activityCouponsProductDTO.setCoverImage(StrUtil.split(activityCouponsProductDTO.getCoverImage(), ",").get(0));
            }
        }
        return activityCouponsProductDTOList;
    }

    /**
     * 获取可添加至优惠券下的活动商品列表
     *
     * @param page
     * @param productName
     * @return
     */
    @Override
    public Page<ActivityCouponsProductDTO> getActivityCouponsCanUseProductDTOPage(Page page, String productName) {
        Page<ActivityCouponsProductDTO> activityCouponsCanUseProductDTOPage = mallActivityDao.getActivityCouponsCanUseProductDTOPage(page, productName);
        for (ActivityCouponsProductDTO record : activityCouponsCanUseProductDTOPage.getRecords()) {
            if (StrUtil.isNotBlank(record.getCoverImage())) {
                record.setCoverImage(StrUtil.split(record.getCoverImage(), ",").get(0));
            }
        }
        return activityCouponsCanUseProductDTOPage;
    }

    @Override
    public Page<ActivityShareProductDTO> getActivityShareCanUseProductDTOPage(Page page, String productName, Long daoId) {
        Page<ActivityShareProductDTO> activityShareCanUseProductDTOPage = mallActivityDao.getActivityShareCanUseProductDTOPage(page, productName, daoId);
        for (ActivityShareProductDTO record : activityShareCanUseProductDTOPage.getRecords()) {
            if (StrUtil.isNotBlank(record.getCoverImage())) {
                record.setCoverImage(StrUtil.split(record.getCoverImage(), ",").get(0));
            }
        }
        return activityShareCanUseProductDTOPage;
    }

    @Override
    public MallActivity getById(Long id) {
        return mallActivityDao.getById(id);
    }

    private MallActivity getActivity(Long id) {
        MallActivity activity = mallActivityDao.getById(id);
        Assert.notNull(activity, () -> new GlobalRunTimeException("活动不存在"));
        return activity;
    }


    /**
     * 选择小程序商品
     *
     * @param daoId
     * @param status
     * @param recommend
     * @param approvalStatus
     * @param productName
     * @param showMiniMall
     * @param mp
     * @return
     */
    @Override
    public IPage<MiniMallActivityPageDTO> queryActivityByMiniMall(Long daoId, Boolean status, Boolean recommend, ApprovalStatusEnum approvalStatus, String productName, Boolean showMiniMall, Page mp, Long profitTemplateId) {
        IPage<MiniMallActivityPageDTO> activityByMiniMall = mallActivityDao.queryActivityByMiniMall(daoId, status, recommend, approvalStatus, productName, showMiniMall, mp, profitTemplateId);
        for (MiniMallActivityPageDTO record : activityByMiniMall.getRecords()) {
            record.setCoverImages(StrUtil.split(record.getCoverImage(), ","));
            record.setMainImages(record.getCoverImages().get(0));
        }
        return activityByMiniMall;
    }

    /**
     * 小程序商品详情
     *
     * @param id
     * @return
     */
    @Override
    public ActivityMiniMallDetailVO miniMallDetail(Long id, String openId) {

        MallActivity activity = mallActivityDao.getById(id);
        Assert.notNull(activity, () -> new GlobalRunTimeException("活动已结束"));
        Assert.isTrue(activity.getStatus(), () -> new GlobalRunTimeException("活动已结束"));
        MallProduct product = mallProductService.getById(activity.getProductId());
        ActivityMiniMallDetailVO activityDTO = new ActivityMiniMallDetailVO();
        activityDTO.setActivityId(activity.getId());
        activityDTO.setActivityType(activity.getActivityType());
        activityDTO.setType(product.getType());
        activityDTO.setCategoryId(product.getCategoryId());
        activityDTO.setCoverImages(StrUtil.split(product.getCoverImage(), ","));
        activityDTO.setThumbnail(product.getThumbnail());
        activityDTO.setStatus(activity.getStatus());
        activityDTO.setBuyLimit(activity.getBuyLimit());
        activityDTO.setStartTime(activity.getStartTime());
        activityDTO.setProductCode(product.getProductCode());
        activityDTO.setProductName(product.getProductName());
        activityDTO.setProductDetail(StrUtil.split(product.getProductDetail(), ","));
        activityDTO.setAllReadyStart(DateTime.now().after(activity.getStartTime()));
        if (Objects.nonNull(product.getAttributeId())) {
            // 属性
            MallProductAttribute productAttribute = mallProductAttributeDao.getById(product.getAttributeId());
            if (StringUtils.isNotBlank(productAttribute.getAttributeDetail())) {
                List<AttributeDetailDTO> attributeDetailDTOS = JSONArray.parseArray(productAttribute.getAttributeDetail(), AttributeDetailDTO.class);
                activityDTO.setAttributeDetailDTOList(attributeDetailDTOS);
                activityDTO.setAttributeName(productAttribute.getAttributeName());
            }
        }

        List<MallActivitySpecs> mallActivitySpecs = mallActivitySpecsDao.getByActivityId(activity.getId());
        String salesPrice = mallActivitySpecs.stream().map(MallActivitySpecs::getSalesPrice).min(BigDecimal::compareTo).get().toPlainString();
        activityDTO.setMinPrice(salesPrice);
        activityDTO.setMaxPrice(mallActivitySpecs.stream().map(MallActivitySpecs::getSalesPrice).max(BigDecimal::compareTo).get().toPlainString());
        if (mallActivitySpecs.size() > 1) {
            salesPrice += "起";
        }
        activityDTO.setSalesPrice(salesPrice);
        List<ActivitySpecsVO> specsDTOS = Lists.newArrayList();
        int sumUsableCount = 0;
        int sumCount = 0;
        for (MallActivitySpecs mallActivitySpec : mallActivitySpecs) {
            ActivitySpecsVO activitySpecsDTO = new ActivitySpecsVO();
            activitySpecsDTO.setActivitySpecsId(mallActivitySpec.getId());
            MallProductSpecs specs = mallProductSpecsDao.getById(mallActivitySpec.getSpecsId());
            if (StringUtils.isNotBlank(specs.getApiProductElementInfo())) {
                ElementInfoDTO elementInfoDTO = JSON.parseObject(specs.getApiProductElementInfo(), ElementInfoDTO.class);
                activitySpecsDTO.setElementInfoDTO(elementInfoDTO);
            }
            activitySpecsDTO.setThumbnail(specs.getThumbnail());
            activitySpecsDTO.setSpecsName(specs.getSpecsName());
            activitySpecsDTO.setSpecsCode(specs.getSpecsCode());
            activitySpecsDTO.setSalesPrice(mallActivitySpec.getSalesPrice().toPlainString());
            activitySpecsDTO.setUsableCount(mallActivitySpec.getUsableStockCount());
            sumUsableCount += mallActivitySpec.getUsableStockCount();
            sumCount += mallActivitySpec.getSumStockCount();
            specsDTOS.add(activitySpecsDTO);
        }
        activityDTO.setSumCount(sumCount);
        activityDTO.setStockEnough(sumUsableCount > 0);
        activityDTO.setActivitySpecs(specsDTOS);
        if (activity.getParticipants() == ParticipantsEnum.APPOINT && activity.getCollectionId() != null && activity.getCollectionId() > 0 && !StringUtils.isEmpty(openId)) {
            WxMiniUserInfo wxMiniUserInfo = wxMiniUserInfoDao.getByOpenId(openId);
            if (Objects.nonNull(wxMiniUserInfo)) {
                DigitalCollection collection = digitalCollectionDao.getById(activity.getCollectionId());
                if (Objects.nonNull(collection)) {
                    Integer count = userCollectionDao.getByUserIdAndCollectionIdCount(wxMiniUserInfo.getUserId(), activity.getCollectionId());
                    if (count == null || count == 0) {
                        activityDTO.setCheckBuy(Boolean.FALSE);
                    }
                    //查询会员权益中是否绑定了该藏品id
                    MallMember mallMember = mallMemberDao.getByCollectionId(activity.getCollectionId());
                    if (Objects.nonNull(mallMember)) {
                        activityDTO.setExclusivePurchase(MiniMallMemberEquityEnums.getEnumByBlurName(mallMember.getMemberName()));
                    }
                }
            }
        }
        //判断是否的积分
        PointsRuleDetailsVO pointsRuleDetailsVO = wxMiniPointsRuleClient.pointsRuleDetails();
        if (Objects.nonNull(pointsRuleDetailsVO)) {
            BigDecimal consumeReward = pointsRuleDetailsVO.getConsumeReward();
            BigDecimal price = mallActivitySpecs.stream().min(Comparator.comparing(MallActivitySpecs::getSalesPrice)).get().getSalesPrice();
            activityDTO.setPredictPoints(price.multiply(consumeReward).setScale(2, RoundingMode.DOWN));
        }
        IdRequest idRequest = new IdRequest();
        idRequest.setId(id);
        activityDTO.setShareGoods(wxMiniProfitTemplateClient.checkGoodsBind(idRequest));
        return activityDTO;
    }


    /**
     * 小程序商品下拉框
     *
     * @param id
     * @param productName
     * @return
     */
    @Override
    public List<QueryMiniMallActivitySelectDTO> QueryMiniMallActivitySelect(Long id, String productName) {
        return mallActivityDao.QueryMiniMallActivitySelect(id, productName);
    }

    /**
     * 标签选择活动商品
     *
     * @param productName
     * @param categoryId
     * @param startTime
     * @param endTime
     * @param mp
     * @return
     */
    @Override
    public IPage<MallGoodsLabelQueryPageDTO> queryByMallLabel(String productName, Long categoryId, Date startTime, Date endTime, Page mp) {
        return mallActivityDao.queryByMallLabel(productName, categoryId, startTime, endTime, mp);
    }
}